import 'dart:async';
import 'dart:io';

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_blue/flutter_blue.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:realmega_ota/realmega/update_widget.dart';
import 'package:realmega_ota/util/ble_manager.dart';
import 'package:realmega_ota/realmega/ota_manager.dart';
import 'package:realmega_ota/realmega/running_log_manager.dart';
import 'package:realmega_ota/realmega/setting_and_filter_manager.dart';

import '../util/log_util.dart';
import 'ota_manager_ex.dart';

class BleWidget extends StatefulWidget {
  final ScanResult result;
  // final BluetoothDevice device;
  final VoidCallback onTap;

  const BleWidget({super.key, required this.result, required this.onTap});

  @override
  State<StatefulWidget> createState() {
    return _BleState();
  }
}

class _BleState extends State<BleWidget> {
  BluetoothDeviceState _state = BluetoothDeviceState.disconnected;
  bool _inUpdate = false;
  double _progress = 0;
  // bool _serviceDiscovered = false;

  StreamSubscription<BluetoothDeviceState>? _bleStateControl;

  @override
  void initState() {
    super.initState();
    _bleStateControl = widget.result.device.state.listen((event) {
      if (event == _state) {
        return;
      }
      Log.d(
          'hashcode:$hashCode, ble ${widget.result.device.name} curState :$event， oldState:$_state');
      _state = event;
      if (event == BluetoothDeviceState.connected) {
        OtaManager.init();
        _requestBleInfo();
      } else if (event == BluetoothDeviceState.disconnected) {
        RunningLogManager.instance
            .addLog("ble ${widget.result.device.name} disconnect");
        // _serviceDiscovered = false;
        _services = null;
        _findCount = 0;
      }
      if (mounted) {
        setState(() {});
      }
    });

    OtaManagerEx.instance.inUpdate.listen((event) {
      _inUpdate = event;
      if (mounted) {
        setState(() {});
      }
    });

    OtaManagerEx.instance.progress.listen((event) {
      _progress = event / 100;
      if (mounted) {
        setState(() {});
      }
    });
    Log.d(
        'otaMac: ${OtaManager.instance.randMacStr}, deviceMac:${widget.result.device.id.toString().toUpperCase()}');
    if (widget.result.device.id.toString().toUpperCase() ==
            OtaManager.instance.randMacStr ||
        widget.result.device.name == 'ble_ota') {
      Log.d("二阶段随机地址，自动连接");
      _connectToDevice(true);
    }
  }

  _requestBleInfo() {
    RunningLogManager.instance.addLog('延时100ms开始请求mtu');
    Future.delayed(const Duration(milliseconds: 100), () {
      RunningLogManager.instance.addLog('开始请求mtu');
      if (Platform.isIOS) {
        _discoverServices();
      } else {
        widget.result.device
            .requestMtu(247)
            .whenComplete(() => _discoverServices())
            .then((value) => RunningLogManager.instance.addLog('请求mtu成功'))
            .onError((error, stackTrace) =>
                RunningLogManager.instance.addLog('请求mtu报错：$error'))
            .catchError(
                (err) => RunningLogManager.instance.addLog('请求mtu异常：$err'));
      }
    });
  }

  int _findCount = 0;
  final int _max_find_count = 5;
  List<BluetoothService>? _services;
  _discoverServices() {
    RunningLogManager.instance.addLog('mtu请求完成');
    if (_services != null) {
      RunningLogManager.instance.addLog('服务已发现：${_services?.length}');

      afterDiscoverService(_services!);

      return;
    }
    Fluttertoast.showToast(msg: '服务查找中，请稍后...');
    Future.delayed(const Duration(milliseconds: 1000), () {
      RunningLogManager.instance.addLog('开始刷新服务');
      _findCount += 1;
      widget.result.device.discoverServices().then((value) {
        // if(_services == value){
        //   RunningLogManager.instance.addLog('服务已经找到');
        //   afterDiscoverService(value);
        //   return;
        // }
        RunningLogManager.instance.addLog('服务已经找到：${value.length}');
        _services = value;

        afterDiscoverService(value);
      }).onError((error, stackTrace) {
        BleManager.disconnect(widget.result.device);
      }).catchError((err) {
        BleManager.disconnect(widget.result.device);
      }).timeout(const Duration(milliseconds: 3000), onTimeout: () {
        if (_findCount > _max_find_count) {
          Log.d('查找不到服务，断开设备');
          widget.result.device.disconnect();
          return;
        }
        _discoverServices();
      });
    });
  }

  void afterDiscoverService(List<BluetoothService> value) {
    if (OtaManager.instance.isOtaDevice(widget.result.device, value)) {
      OtaManager.instance.startOta();
    } else {
      RunningLogManager.instance.addLog('没找到OTA服务');
      Fluttertoast.showToast(msg: '没找到OTA服务');
      BleManager.disconnect(widget.result.device);
    }

    if (mounted) {
      setState(() {});
    }
  }

  @override
  void dispose() {
    super.dispose();
    _state = BluetoothDeviceState.disconnected;
    _bleStateControl?.cancel();
  }

  @override
  Widget build(BuildContext context) {
    return ExpansionTile(
      title: Transform(
        transform: Matrix4.translationValues(-20, 0.0, 0.0),
        child: _buildTitle(context),
      ),
      subtitle: Transform(
        transform: Matrix4.translationValues(-20, 0.0, 0.0),
        child: _buildProgressInfo(context),
      ),
      leading: const Icon(
        Icons.bluetooth,
        color: Colors.blueAccent,
      ),
      trailing: _buildConnectStateWidget(),
      children: <Widget>[
        _buildAdvRow(context, 'Complete Local Name',
            widget.result.advertisementData.localName),
        _buildAdvRow(context, 'Tx Power Level',
            '${widget.result.advertisementData.txPowerLevel ?? 'N/A'}'),
        _buildAdvRow(
            context,
            'Manufacturer Data',
            getNiceManufacturerData(
                    widget.result.advertisementData.manufacturerData) ??
                'N/A'),
        _buildAdvRow(
            context,
            'Service UUIDs',
            (widget.result.advertisementData.serviceUuids.isNotEmpty)
                ? widget.result.advertisementData.serviceUuids
                    .join(', ')
                    .toUpperCase()
                : 'N/A'),
        _buildAdvRow(
            context,
            'Service Data',
            getNiceServiceData(widget.result.advertisementData.serviceData) ??
                'N/A'),
        _buildUpdateWidget(),
      ],
    );
  }

  Widget _buildUpdateWidget() {
    if (_inUpdate && widget.result.device == OtaManager.instance.otaDevice) {
      return const UpdateWidget();
    }
    return Container();
  }

  Widget _buildConnectStateWidget() {
    if (_inUpdate && widget.result.device == OtaManager.instance.otaDevice) {
      return CircularProgressIndicator(
        value: _progress,
        backgroundColor: Colors.black12,
        valueColor: const AlwaysStoppedAnimation<Color>(Colors.blueAccent),
      );
    }
    switch (_state) {
      case BluetoothDeviceState.disconnected:
        return ElevatedButton(
          child: const Text('CONNECT'),
          onPressed: () {
            Log.d("设备未连接，点击连接");
            _connectToDevice(false);
            // widget.onTap();
          },
        );
      case BluetoothDeviceState.connected:
        return ElevatedButton(
          child: const Text('DISCONNECT'),
          onPressed: () {
            Log.d("设备已连接，点击断开");
            BleManager.disconnect(widget.result.device);
            _state = BluetoothDeviceState.disconnected;
            // _serviceDiscovered = false;
            setState(() {});
            // widget.onTap();
          },
        );
      default:
        return const CupertinoActivityIndicator();
    }
  }

  _connectToDevice(bool isAuto) {
    BleManager.connect(widget.result.device).onError((error, stackTrace) {
      Fluttertoast.showToast(msg: '连接失败');
    }).timeout(const Duration(seconds: 8), onTimeout: () {
      _state = BluetoothDeviceState.disconnected;
      if (mounted) {
        setState(() {});
      }
      if (isAuto) {
        RunningLogManager.instance.addLog('二阶段连接失败，自动重连');
        _connectToDevice(true);
      } else {
        Fluttertoast.showToast(msg: '连接超时');
      }
    });
    _state = BluetoothDeviceState.connecting;
    if (mounted) {
      setState(() {});
    }
  }

  Widget _buildTitle(BuildContext context) {
    if (widget.result.device.name.isNotEmpty) {
      return Column(
        mainAxisAlignment: MainAxisAlignment.start,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          Text(
            '${widget.result.device.name}(rssi:${widget.result.rssi})',
            overflow: TextOverflow.ellipsis,
          ),
          Text(
            widget.result.device.id.toString(),
            style: Theme.of(context).textTheme.bodySmall,
          )
        ],
      );
    } else {
      return Text(
          '${widget.result.device.id.toString()}(rssi:${widget.result.rssi})');
    }
  }

  Widget _buildProgressInfo(BuildContext context) {
    if (_inUpdate && widget.result.device == OtaManager.instance.otaDevice) {
      return Text('current progress: ${(_progress * 100).toInt()}');
    } else {
      return Container();
    }
  }

  Widget _buildAdvRow(BuildContext context, String title, String value) {
    return Padding(
      padding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 4.0),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          Text(title, style: Theme.of(context).textTheme.caption),
          SizedBox(
            width: 12.0,
          ),
          Expanded(
            child: Text(
              value,
              style: Theme.of(context)
                  .textTheme
                  .caption
                  ?.apply(color: Colors.black),
              softWrap: true,
            ),
          ),
        ],
      ),
    );
  }

  String getNiceHexArray(List<int> bytes) {
    return '[${bytes.map((i) => i.toRadixString(16).padLeft(2, '0')).join(', ')}]'
        .toUpperCase();
  }

  String? getNiceManufacturerData(Map<int, List<int>> data) {
    if (data.isEmpty) {
      return null;
    }
    List<String> res = [];
    data.forEach((id, bytes) {
      res.add(
          '${id.toRadixString(16).toUpperCase()}: ${getNiceHexArray(bytes)}');
    });
    return res.join(', ');
  }

  String? getNiceServiceData(Map<String, List<int>> data) {
    if (data.isEmpty) {
      return null;
    }
    List<String> res = [];
    data.forEach((id, bytes) {
      res.add('${id.toUpperCase()}: ${getNiceHexArray(bytes)}');
    });
    return res.join(', ');
  }
}
